//
//  ViewController.m
//  TestObjc
//
//  Created by pier on 12-5-30.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import "ViewController.h"
#import "DLog.h"
#import "DenominatorNotZeroException.h"
#import "Person.h"
#import "SellTickets.h"
#import "SellTickets2.h"
#import "SellTickets3.h"
#import "SellTicketsOperation.h"

@implementation ViewController

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    
    ticketsCondition = [[NSCondition alloc] init];
    queue = [[NSOperationQueue alloc]init];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    
    [ticketsCondition release];
    ticketsCondition = nil;
    [queue release];
    queue = nil;
}

-(void)dealloc{
    [ticketsCondition release];
    [queue release];
    [super dealloc];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
	[super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
	[super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

#pragma mark - test
- (IBAction)simpleTest {
    //NSRange
    NSRange range;
    range.location = 10;
    range.length = 20;
    NSLog(@"range:%d,%d", range.location, range.length);
    LogRange(@"range", range);
    
    NSRange range2 = {15, 10};
    LogRange(@"range2", range2);
    
    LogRange(@"range3", NSMakeRange(12, 19));
    
    //CGPoint
    CGPoint point;
    point.x = 10.0f;
    point.y = 10.0f;
    LogPoint(@"point", point);
    LogPoint(@"pooint", CGPointMake(15, 15));
    
    //equal compare
    bool rst = CGPointEqualToPoint(point, CGPointMake(10, 10));
    
    {// to string
        NSString *str = NSStringFromCGPoint(point);
        LogStr(str);
        Log(@"%@", str);
        LogPoint(@"", CGPointFromString(str));
    }
    
    //    CGSize
    CGSize size;
    size.width = 12.0;
    size.height = 10;
    LogSize(@"size", size);
    LogSize(@"size2", CGSizeMake(14, 14));
    //equal compare
    rst = CGSizeEqualToSize(size, CGSizeMake(15, 15));
    
    {// to string
        NSString *str = NSStringFromCGSize(size);
        Log(@"%@", str);
        LogSize(@"", CGSizeFromString(str));
    }
    
    //    CGRect
    CGRect rect;
    rect.origin = point;
    rect.size = size;
    LogRect(@"rect", rect);
    
    //inset
    CGRect r = CGRectInset(rect, 1, 1);
    LogRect(@"rect", r);
    r = CGRectInset(rect, -1, -1);
    LogRect(@"rect", r);
    LogRect(@"rect", CGRectMake(10, 10, 12, 12));
    
    //equal compare
    rst = CGRectEqualToRect(rect, rect);
    
    //rect to str
    NSString *str = NSStringFromCGRect(rect);
    Log(@"%@", str);
    CGRect rect2 = CGRectFromString(str);
    LogRect(@"rect2", rect2);
    
    //intersets
	rst = CGRectIntersectsRect(rect, rect2);
    
//    NSNumber
    //NSNumber可以将基本数据类型包装起来，形成一个对象
    NSNumber *iv = [NSNumber numberWithInt:10];
    Log(@"%d", [iv intValue]);
    
    NSNumber *iv2 = [[NSNumber alloc] initWithInt:11];
    Log(@"%d", [iv2 intValue]);
    [iv2 release];
    
//    NSValue
    //NSNumber实际上是NSValue的子类，NSValue可以包装任意值
    //使用NSValue只能是对那些没有变量是指针的struct
    //方便了某些对象加入到集合中
    {
        typedef struct {
            float real;
            float imaginary;
        } ImaginaryNumber;
        
        ImaginaryNumber miNumber;
        miNumber.real = 1.1;
        miNumber.imaginary = 1.41;
        
        //NSValue *miValue = [NSValue valueWithBytes:&miNumber objCType:@encode(ImaginaryNumber)];
        NSValue *miValue = [NSValue value:&miNumber withObjCType:@encode(ImaginaryNumber)]; 
        
        NSMutableArray *marr = [[NSMutableArray alloc] init];
        [marr addObject:miValue];
        [marr addObject:[NSNull null]]; //添加一个NSNull
        Log(@"%@", marr);
        NSValue *val = [marr objectAtIndex:0];
        ImaginaryNumber miNumber1;
        [val getValue:&miNumber1];
        Log(@"%@", val);
        [marr release];
        
        ImaginaryNumber miNumber2;
        [miValue getValue:&miNumber2];
        Log(@"wahh");
    }
    
    
//    NSNull
    //因为在NSArray和NSDictionary中nil中有特殊的含义（表示列表结束）
    //如要确实需要存储一个表示“什么都没有”的值，可以使用NSNull类
    //NSNull只有一个方法：+ (NSNull *) null;
    
//    NSData
    //NSData常用语二进制文件操作
    //还可以和UIImage
    {
        //NSString
        NSString *aString = @"1234abcd";
        NSData *aData = [aString dataUsingEncoding: NSUTF8StringEncoding];
        NSString *aString1 = [[NSString alloc] initWithData:aData encoding:NSUTF8StringEncoding];
        LogStr(aString1);
        [aString1 release];
        
        //Byte
        Byte *bytes = [aData bytes];
        for (int i=0; i<[aData length]; i++) {
            Log(@"%c", bytes[i]);
        }
//        
//        NSData *byteData = [[NSData alloc] initWithBytes:bytes length:strlen(bytes)];
//        NSString *str = [[NSString alloc] initWithData:byteData encoding:NSUTF8StringEncoding];
//        LogStr(str);
//        [str release];        
    }
}


#pragma mark - excetpion

- (void)zero{
    int i = 0;
    i = 5/1;
    i = 5/0;
}

- (void)zero1{
    int i = 0;
    if( i == 0 )
    {
        NSException *e = [DenominatorNotZeroException exceptionWithName: @"DenominatorNotZeroException" reason: @"The denominator is not 0!" userInfo:nil];
        @throw e;
    }
}

- (void)zero2{
    int i = 0;
    if( i == 0 )
    {
        NSException *e = [NSException exceptionWithName: @"NSException" reason: @"The denominator is not 0!" userInfo:nil];
        @throw e;
    }
}

- (IBAction)exceptionTest {
    @try{
        [self zero];
    }
    @catch (DenominatorNotZeroException *dne){
        LogException(@"", dne);
    }
    @catch (NSException *e){ 
        LogException(@"", e);
    }
    @finally{
        printf("finally run!\n");
    }
    
    @try{
        [self zero1];
    }
    @catch (DenominatorNotZeroException *dne){
        LogException(@"", dne);
    }
    @catch (NSException *e){ 
        LogException(@"", e);
    }
    @finally{
        printf("finally run!\n");
    }
    
    @try{
        [self zero2];
    }
    @catch (DenominatorNotZeroException *dne){
        LogException(@"", dne);
    }
    @catch (NSException *e){ 
        LogException(@"", e);
    }
    @finally{
        printf("finally run!\n");
    }
}

#pragma mark - string
- (IBAction)stringTest {
    
//    – doubleValue
//    – floatValue
//    – intValue
//    – integerValue
//    – longLongValue
//    – boolValue
    
    //创建字符串
    //    1、创建常量字符串。 
    {
        NSString *astring = @"This is a String!";  
        NSLog(@"astring:%@",astring); 
    }
    
    //    2、创建空字符串，给予赋值。  
    {
        NSString *astring = [[NSString alloc] init];  
        [astring release];
        astring = nil;
        astring = @"This is a String!";  
        NSLog(@"astring:%@",astring);  
    }
    
    //    3、在以上方法中，提升速度:initWithString方法  
    {
        NSString *astring = [[NSString alloc] initWithString:@"This is a String!"];  
        NSLog(@"astring:%@",astring);  
        [astring release];  
    }
    
    //    4、用标准c创建字符串:initWithCString方法  
    {
        char *Cstring = "This is a String!";  
        NSString *astring = [[NSString alloc] initWithCString:Cstring];  
        NSLog(@"astring:%@",astring);  
        [astring release];  
    }
    
    //    5、创建格式化字符串:占位符（由一个%加一个字符组成） 
    {
        int i = 1;  
        int j = 2;  
        NSString *astring = [NSString stringWithFormat:@"%d.This is %i string!",i,j];  
        NSLog(@"astring:%@",astring);    
    }
    
    //    6、创建临时字符串  
    {
        NSString *astring;  
        astring = [NSString stringWithCString:"This is a temporary string"];  
        NSLog(@"astring:%@",astring);
    }
    
    /*----------------从文件读取字符串:initWithContentsOfFile方法 ----------------*/  
    //路径问题
    {
        NSString *path = @"~/wwp.log";  
        LogStr([path stringByExpandingTildeInPath]);
        LogStr([path pathExtension]);
        NSString *astring = [[NSString alloc] initWithContentsOfFile:path];  
        NSLog(@"astring:%@",astring);  
        [astring release];  
    }
    
    /*----------------从网页中读取字符串 ----------------*/  
    {
        NSString *path = @"www.baidu.com";  
        NSString *astring = [[NSString alloc] initWithContentsOfFile:path usedEncoding:NSUTF8StringEncoding error:nil];
        NSLog(@"astring:%@",astring);  
        [astring release];  
    }
    
    /*----------------写字符串到文件:writeToFile方法 ----------------*/  
    {
        NSString *astring = [[NSString alloc] initWithString:@"This is a String!"];  
        NSLog(@"astring:%@",astring);  
        NSString *path = @"~/astring.text";  
        [astring writeToFile: path atomically: YES];  
        [astring release]; 
    }
    
    /*---------------- 比较两个字符串----------------*/  
    //    用C比较:strcmp函数  
    {
        char string1[] = "string!";  
        char string2[] = "string!";  
        if(strcmp(string1, string2) == 0)  
        {  
            NSLog(@"1");  
        }  
    }
    
    //    isEqualToString方法  
    {
        NSString *astring01 = @"This is a String!";  
        NSString *astring02 = @"This is a String!";  
        BOOL result = [astring01 isEqualToString:astring02];  
        NSLog(@"result:%d",result);  
    }
    
    //    compare方法(comparer返回的三种值)  
    {
        NSString *astring01 = @"This is a String!";  
        NSString *astring02 = @"This is a String!";  
        BOOL result = [astring01 compare:astring02] == NSOrderedSame;  //NSOrderedSame 判断两者内容是否相同  
        NSLog(@"result:%d",result);  
    }
    
    {
        NSString *astring01 = @"This is a String!";  
        NSString *astring02 = @"this is a String!";  
        BOOL result = [astring01 compare:astring02] == NSOrderedAscending;  
        NSLog(@"result:%d",result);  
        //NSOrderedAscending 判断两对象值的大小(按字母顺序进行比较，astring02大于astring01为真) 
    }
    
    {
        NSString *astring01 = @"this is a String!";  
        NSString *astring02 = @"This is a String!";  
        BOOL result = [astring01 compare:astring02] == NSOrderedDescending;  
        NSLog(@"result:%d",result);  
        //NSOrderedDescending 判断两对象值的大小(按字母顺序进行比较，astring02小于astring01为真)  
    }
    
    //    不考虑大 小写比较字符串1  
    {
        NSString *astring01 = @"this is a String!";  
        NSString *astring02 = @"This is a String!";  
        BOOL result = [astring01 caseInsensitiveCompare:astring02] == NSOrderedSame;  
        NSLog(@"result:%d",result);  
        //NSOrderedDescending判断两对象值的大小(按字母顺序进行比较，astring02小于astring01为 真)  
    }
    
    //    不考虑大小写比较字符串2  
    {
        NSString *astring01 = @"this is a String!";  
        NSString *astring02 = @"This is a String!";  
        BOOL result = [astring01 compare:astring02  
                                 options:NSCaseInsensitiveSearch | NSNumericSearch] == NSOrderedSame;  
        NSLog(@"result:%d",result);       
        
        //NSCaseInsensitiveSearch:不区分大小写比较 NSLiteralSearch:进行完全比较，区分大小写 NSNumericSearch:比较字符串的字符个数，而不是字符值。  
    }
    
    /*----------------改变字符串的大小写----------------*/ 
    {
        NSString *string1 = @"A String";  
        NSString *string2 = @"String";  
        NSLog(@"string1:%@",[string1 uppercaseString]);//大写  
        NSLog(@"string2:%@",[string2 lowercaseString]);//小写  
        NSLog(@"string2:%@",[string2 capitalizedString]);//首字母大小  
    }
    
    /*----------------在串中搜索子串 ----------------*/  
    {
        NSString *string1 = @"This is a string";  
        NSString *string2 = @"string";  
        NSRange range = [string1 rangeOfString:string2];  
        LogRange(@"", range);
        
        //hasPrefix
        BOOL rst = NO;
        rst = [string1 hasPrefix:@"This"];
        Log(@"%d", rst);
        
        //hasSuffix
        rst = [string1 hasSuffix:@"string"];
        Log(@"%d", rst);
    }
    
    /*----------------抽取子串 ----------------*/  
    {
        //    -substringToIndex: 从字符串的开头一直截取到指定的位置，但不包括该位置的字符  
        NSString *string1 = @"This is a string";  
        NSString *string2 = [string1 substringToIndex:3];  
        NSLog(@"string2:%@",string2);  
    }
    
    //    -substringFromIndex: 以指定位置开始（包括指定位置的字符），并包括之后的全部字符  
    {
        NSString *string1 = @"This is a string";  
        NSString *string2 = [string1 substringFromIndex:3];  
        NSLog(@"string2:%@",string2);  
    }
    
    //    -substringWithRange: //按照所给出的位置，长度，任意地从字符串中截取子串  
    {
        NSString *string1 = @"This is a string";  
        NSString *string2 = [string1 substringWithRange:NSMakeRange(0, 4)];  
        NSLog(@"string2:%@",string2);  
    }
    
    // to utf8 char*
    {
        NSString *value = @"This is a string"; 
        const char *fieldValue = [value  cStringUsingEncoding:NSUTF8StringEncoding];  
        const char *fieldValue2 = [value UTF8String];  
    }
    
    //    NSString 转 NSData 
    {
        NSString* str= @"kilonet";  
        NSData* data=[str dataUsingEncoding:NSUTF8StringEncoding]; 
        
        const char *cs="He is very heigh!";
        data=[NSData dataWithBytes:cs length:strlen(cs)+1 ];
        NSLog(@"%@",data);
    }  
    
    //去处两端空白
    {
        //空格、tab、换行
        NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; 
        //空格、tab
        NSCharacterSet *whitespace1 = [NSCharacterSet whitespaceCharacterSet];
        NSLog(@"%@", whitespace.description);
        
        NSString *str = [NSString stringWithFormat:@"\n hello world! \t 哈哈！ \n 要记住，你是最棒的"];
        LogStr(str);        
        
        //在string中去处某个字符集
        NSString *strRst = [str stringByTrimmingCharactersInSet:whitespace]; 
        LogStr(strRst);
        strRst = [str stringByTrimmingCharactersInSet:whitespace1]; 
        LogStr(strRst);
                
        for (NSUInteger i=0; i<[strRst length]; i++) {
            unichar c = [strRst characterAtIndex:i];
            if( [whitespace characterIsMember:c] )
            {
                printf("yes");
            }
        }
    }
    
    //正则表达式
    {
        NSString *regex = @"^A.+e$";//以 A 开头,以 e 结尾的字符。
        NSPredicate *pre= [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; 
        if([pre evaluateWithObject: @"Apple"]){
            printf("YES\n"); }
        else{
                printf("NO\n"); 
        }
    }
}

- (IBAction)mutableStringTest {
    {   //+stringWithCapacity
        NSMutableString *str = [NSMutableString stringWithCapacity:5];
        [str appendString:@"abcde"];
        LogStr(str);
        [str appendString:@"abcde"];
        LogStr(str);
    }
    
    {
        NSMutableString *str = [[NSMutableString alloc] init];
        [str appendString:@"hello "];
        [str appendString:@"world!"];
        LogStr(str);
        [str setString:@"娃哈哈"];
        LogStr(str);
        [str deleteCharactersInRange:NSMakeRange(0, 2)];
        LogStr(str);
        [str insertString:@"hi," atIndex:0];
        LogStr(str);
        [str replaceCharactersInRange:NSMakeRange(0, [str length]) withString:@"hello world!"];
        LogStr(str);
        [str replaceOccurrencesOfString:@"hello" withString:@"hi," options:NSAnchoredSearch range:NSMakeRange(0, [str length])];
        LogStr(str);
        [str release];
    }
}

#pragma mark - date
//NSDate存储的是世界标准时(UTC)，输出时需要根据时区转换为本地时间。
//NSDateFormatter可以比较方便的进行格式转换
//日历NSCalendar 
//NSDateComponents

//NSDateFormatter使用的时间格式
/*
 G: 公元时代，例如AD公元
 yy: 年的后2位
 yyyy: 完整年
 MM: 月，显示为1-12
 MMM: 月，显示为英文月份简写,如 Jan
 MMMM: 月，显示为英文月份全称，如 Janualy
 dd: 日，2位数表示，如02
 d: 日，1-2位显示，如 2
 EEE: 简写星期几，如Sun
 EEEE: 全写星期几，如Sunday
 aa: 上下午，AM/PM
 H: 时，24小时制，0-23
 K：时，12小时制，0-11
 m: 分，1-2位
 mm: 分，2位
 s: 秒，1-2位
 ss: 秒，2位
 S: 毫秒
 */
- (IBAction)dateTest {
    //NSDate
    //当前时间
    NSDate *now = [NSDate date]; 
    NSLog(@"%@", now);
    LogDate(@"now:", now);
        
    //从现在开始后24小时
    NSTimeInterval secondsPerDay = 24*60*60;
    NSDate *tomorrow = [NSDate dateWithTimeIntervalSinceNow:secondsPerDay];
    
    //根据一个已有日期创建日期
    //从现在开始的前二十四小时
    NSDate *yesterday = [now addTimeInterval:-secondsPerDay];
    
    //比较两个日期是否相等
    BOOL sameDate = [yesterday isEqualToDate:tomorrow];
    
    //判断一个日期在另一个日期之前还是之后
    NSDate *earlierDate = [yesterday earlierDate:tomorrow];
    NSDate *laterDate = [tomorrow laterDate:yesterday];
    
    //两个日期之间间隔秒数
    NSTimeInterval secondsBetweenDates = [tomorrow timeIntervalSinceDate:yesterday];
    NSTimeInterval secondsUntilTomorrow = [tomorrow timeIntervalSinceNow];
    
    
    //日历NSCalendar 
    //通过已有日期创建日期的时候，日历更加容易，因为我们不把所有内容转换为秒
    //从现在开始后24小时
    NSDateComponents *comp = [[NSDateComponents alloc] init];
    [comp setDay:01];
    NSCalendar *myCal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDate *tomorrow1 = [myCal dateByAddingComponents:comp toDate:now options:0];
    [myCal release];
    
    //创建一个表示2010.6.1的日期
    NSDateComponents *comp1 = [[NSDateComponents alloc] init];
    [comp1 setMonth:06];
    [comp1 setDay:01];
    [comp1 setYear:2010];
    NSCalendar *myCal1 = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDate *myDate = [myCal1 dateFromComponents:comp1];
    [myCal1 release];
    
    //从一个已有的日期中，获取年月日
    unsigned units = NSMonthCalendarUnit | NSYearCalendarUnit | NSDayCalendarUnit;
    NSCalendar *myCal2 = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *comp2 = [myCal2 components:units fromDate:now]; 
    [myCal2 release];
    
    //NSDateFormatter 
    //NSDate to NSString
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    NSString *friendlyDate = [formatter stringFromDate:now];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss:SSS"]; //自定义格式
    friendlyDate = [formatter stringFromDate:now];
    [formatter release];
    
    //NSString to NSDate
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; 
    NSDate *date = [dateFormatter dateFromString:@"2010-08-04 16:01:03"]; 
    [dateFormatter release];
}

- (IBAction)timeZoneTest {
    NSArray *timeZoneNames = [NSTimeZone knownTimeZoneNames];  
    NSDate* nowDate = [ NSDate date ];  
    for( NSString* name in timeZoneNames )  
    {  
        NSTimeZone* timename = [ [ NSTimeZone alloc] initWithName:name ];  
        NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init ];  
        [outputFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];  
        [outputFormatter setTimeZone:timename ];  
        NSString *newDateString = [outputFormatter stringFromDate:nowDate];  
        NSLog( @"/nZone: %@,%@",[ timename name ] ,newDateString );  
        //[ timename name ],[ nowDate descriptionWithCalendarFormat:@"%d/%m/%y, %H:%M:%S %z"   
        //   timeZone:timename   
        //   locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]  );  
        [ outputFormatter release ];  
        [ timename release ];  
    } 
}

int count;
- (IBAction)timerTest {
    count = 1;
	[NSTimer scheduledTimerWithTimeInterval: 1.0f target: self selector: @selector(handleTimer:) userInfo: nil repeats: YES];
    
//    //手动启动定时器
//    NSTimer *myTimer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(handleTimer:) userInfo:nil repeats:YES];
//    [[NSRunLoop mainRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode];

}

- (void) handleTimer: (NSTimer *) timer
{
	printf("Timer count: %d\n", count++);
	if (count > 3) 
	{
		[timer invalidate];     //停止定时器
		printf("Timer disabled\n");
	}
}


#pragma mark - collections
- (IBAction)arrayTest {
    //NSArray
    {
        NSArray *array = [[NSArray alloc] initWithObjects:@"one", @"two", @"three", @"four", nil];
        Log(@"%@", array);
        Log(@"count:%d", [array count]);
        LogStr([array objectAtIndex:1]);
        for (NSString *str in array) {
            LogStr(str);
        }
        [array release];
    }
    
    {// sort
        NSArray *arr = [[NSArray alloc] initWithObjects:@"b", @"z", @"a", @"y", nil];
        NSLog(@"%@", arr);
        NSArray *arr1 = [arr sortedArrayUsingSelector:@selector(compare:)];
        NSLog(@"%@", arr1);
        [arr release];
    }
    
    {//joni to string, string split to array
        NSArray *arr = [[NSArray alloc] initWithObjects:@"one", @"two", @"three", nil];
        NSString *str = [arr componentsJoinedByString:@","];
        NSLog(@"%@", arr);
        NSLog(@"%@", str);
        [arr release];
        
        NSArray *arr1 = [str componentsSeparatedByString:@","];
        NSLog(@"%@", arr1);
    }
    
    {//NSEnumerator
        NSArray *arr = [[NSArray alloc] initWithObjects:@"a", @"b", @"c", @"d", nil];
        NSEnumerator *enu = [arr objectEnumerator];
        id str;
        while (str = [enu nextObject]) {
            NSLog(@"%@", str);
        }
        
        NSEnumerator *enu2 = [arr reverseObjectEnumerator];
        id str2;
        while (str2 = [enu2 nextObject]) {
            NSLog(@"%@", str2);
        }
        [arr release];
    }
    
    //NSMutableArray
    {
        NSMutableArray *marr = [[NSMutableArray alloc] initWithObjects:@"a", @"b", @"c", nil];
        NSLog(@"%@", marr);
        [marr addObject:@"d"];
        NSLog(@"%@", marr);
        [marr removeObjectAtIndex:0];
        NSLog(@"%@", marr);
        [marr removeLastObject];
        NSLog(@"%@", marr);
        [marr insertObject:@"e" atIndex:0];   
        NSLog(@"%@", marr);
    }
}

- (IBAction)setTest {
    NSSet *set = [[NSSet alloc] initWithObjects:@"a", @"b", @"a", @"c", nil];
    Log(@"%@", set);
    Log(@"%d",[set count]);
    Log(@"%d", [set containsObject:@"a"]);
    LogStr([set anyObject]);
//    [set release];
    
    NSMutableSet *mset = [[NSMutableSet alloc] initWithSet:set];
    [mset addObject:@"e"];
    [mset removeObject:@"a"];
    [mset release];
    [set release];
}

- (IBAction)dictTest {
    //NSDictionary
    {
        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"one", @"a", @"two", @"b", nil];
        NSLog(@"%@", dict);
        Log(@"%d", [dict count]);
        Log(@"%@", [dict allKeys]);
        Log(@"%@", [dict allValues]);
        Log(@"%@", [dict allKeysForObject:@"one"]);
        LogStr([dict objectForKey:@"a"]);
        LogStr([dict objectForKey:@"c"]);
        
        NSEnumerator* kenu = [dict keyEnumerator];
        id key;
        while (key = [kenu nextObject]) {
            LogStr(key);
        }
        
        NSEnumerator* oenu = [dict objectEnumerator];
        id obj;
        while (obj = [oenu nextObject]) {
            LogStr(obj);
        }
    }
    
    //NSMutableDictionary
    {
        NSMutableDictionary *mdict = [[NSMutableDictionary alloc] initWithCapacity:10];
        [mdict setObject:@"one" forKey:@"a"];
        Log(@"%@", mdict);
        [mdict setObject:@"one" forKey:@"b"];
        Log(@"%@", mdict);
        [mdict setObject:@"11" forKey:@"a"];
        Log(@"%@", mdict);
        [mdict removeObjectForKey:@"a"];
        Log(@"%@", mdict);
        [mdict removeAllObjects];
        Log(@"%@", mdict);
        [mdict release];
    }
}


#pragma mark - memoryManage
- (IBAction)memoryManage {
    //自动释放
    {
        NSString *str = @"hello";
        NSString *str1 = [NSString stringWithString:@"hello"];
        NSString *str2 = str;
        NSString *str3 = [[[NSString alloc] initWithString:@"hello"] autorelease];
    }
    
    //函数返回值
    //如果函数会返回一个新建的对象，该对象的所有权还是属于函数的
    {
        NSString *str = [self getString];
        LogStr(str);
    }
    
    //集合    
    //一般的情况下，集合获得对象的所有权
    {
        NSMutableArray *marray = [[NSMutableArray alloc] init];
        
        NSString *str = [[NSString alloc] initWithString:@"hello"];
        [marray addObject:str]; //获取对象所有权
        [str release];
        
        NSString *str1 = [[[NSString alloc] initWithString:@"world"] autorelease];
        [marray addObject:str1];
        
        NSString *str2 = [[NSString alloc] initWithString:@"!"];
        [marray addObject:str2];
        [marray addObject:str2];
        [marray addObject:str2];
        [str2 release];
        NSLog(@"%@", marray);
        
        [marray removeLastObject];  //释放对象所有权
        NSLog(@"%@", marray);
                
        [marray release];   //释放所有包含对象的所有权
    }
}

//对象的内存管理，最关键的就是对象的”所有权“
- (NSString *)getString{
    NSString *str = [[NSString alloc] initWithString:@"hello"];
    return [str autorelease];
}

#pragma mark - copyTest
//http://woshao.com/article/f91898b24a1211e097d3000c2959fd2a/
//深浅拷贝分别指深拷贝和浅拷贝，即mutableCopy和copy方法
//copy复制一个不可变对象，而mutableCopy复制一个mutable可变对象。
- (IBAction)copyTest {
    //非容器类对象
    {//如果对一个不可变对象复制，copy是指针复制，即浅拷贝；而mutableCopy则是对象复制，即深拷贝。
        NSString *str = @"origin string";
        NSString *strCopy = [str copy];
        NSMutableString *mstrCopy = [str mutableCopy];
        [mstrCopy appendString:@"??"];
        LogStr(str);
        LogStr(strCopy);
        LogStr(mstrCopy);
        [strCopy release];
        [mstrCopy release];
        
        //str和strCopy指向的是同一块内存区域，我们称之为弱引用（weak reference）
        //而mstrCopy是真正的复制，系统为其分配了新内存空间
    }
    
    {//如果是对可变对象复制，都是深拷贝，但copy复制返回的对象是不可变的
        NSMutableString *mstr = [NSMutableString stringWithString:@"origin"];
        NSString *strCopy = [mstr copy];
        NSMutableString *mstrCopy = [mstr copy];
        NSMutableString *mstrMCopy = [mstr mutableCopy];
        //[mstrCopy appendString:@"1111"];  //error
        [mstr appendString:@"222"];
        [mstrMCopy appendString:@"333"];
        LogStr(mstr);
        LogStr(strCopy);
        LogStr(mstrCopy);
        LogStr(mstrMCopy);
        [strCopy release];
        [mstrCopy release];
        [mstrMCopy release];
        //以上四个对象所分配的内存都是不一样的。
        //而且对于mstrCopy，它所指向的其实是一个imutable对象，是不可改变的，所以会出错。
    }
    
    //容器类对象深浅复制
    //对于容器而言，其元素对象始终是指针复制。如果需要元素对象也是对象复制，就需要实现深拷贝
    {
        /* copy返回不可变对象，mutablecopy返回可变对象 */
        
        NSArray *array1     = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
        NSArray *arrayCopy1 = [array1 copy];
        //arrayCopy1是和array同一个NSArray对象（指向相同的对象），包括array里面的元素也是指向相同的指针
                
        NSMutableArray *mArrayCopy1 = [array1 mutableCopy];
        //mArrayCopy1是array1的可变副本，指向的对象和array1不同，但是其中的元素和array1中的元素指向的还是同一个对象。mArrayCopy1还可以修改自己的对象
        [mArrayCopy1 addObject:@"de"];
        [mArrayCopy1 removeObjectAtIndex:0];
        [arrayCopy1 release];
        [mArrayCopy1 release];
    }
    
    {
        NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
        NSArray *mArrayCopy2 = [mArray1 copy];
        // mArray1和mArrayCopy2指向同一对象，retain值+1。
        
        NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];
        //mArrayCopy2和mArray1指向的是不一样的对象，但是其中的元素都是一样的对象——同一个指针
        
        NSMutableString *testString = [mArray1 objectAtIndex:0];
        //testString = @"1a1";//这样会改变testString的指针，其实是将@“1a1”临时对象赋给了testString
        [testString appendString:@" tail"];//这样以上三个数组的首元素都被改变了
        [mArrayMCopy1 addObject:@"3"];
        [mArrayMCopy1 addObject:@"4"];
        [mArrayCopy2 release];
        [mArrayMCopy1 release];
    }
}

#pragma mark - predicate
- (IBAction)predicateTest {
    //Cocoa 提供了 NSPredicate 用于指定过滤条件,谓词是指在计算机中表示计算真假值的函数
    //它使用起来有点儿像 SQL 的查询条件,主要用于从集合中分拣出符合条件的对象,也可以 用于字符串的正则匹配
    
    NSMutableArray *marr = [[[NSMutableArray alloc] init] autorelease];
    [marr addObject:[[Person personWithPid:1 Name:@"zhangsan" Height:170]autorelease]];
    [marr addObject:[[Person personWithPid:2 Name:@"lisi" Height:180]autorelease]];
    [marr addObject:[[Person personWithPid:3 Name:@"王五" Height:175]autorelease]];
    [marr addObject:[[Person personWithPid:4 Name:@"赵六" Height:190]autorelease]];
    [marr addObject:[[Person personWithPid:5 Name:@"whh" Height:200]autorelease]];
    [marr addObject:[[Person personWithPid:6 Name:@"ZHANGhan" Height:160]autorelease]];
    
//    逻辑运算符:AND、OR、NOT
    //AND
    //创建谓词,条件是 pid>1 并且 height<188.0。
    //其实谓词也是基于 KVC 的,也就是如 果 pid 在 person 的成员变量 xxx 中,那么此处要写成 xxx.pid>1。
    [self doPredicateTest:marr :@"and" :@"pid>1 and height<188.0"];
    [self doPredicateTest:marr :@"or" :@"pid>1 or height<188.0"];
    [self doPredicateTest:marr :@"not" :@"not pid>1"];
    
//    范围运算符:BETWEEN、IN
    [self doPredicateTest2:marr :@"BETWEEN" :@"pid between {2,4}"];
    [self doPredicateTest2:marr :@"IN" :@"name in {'Name1','zhangsan', 'lisi'}"];
    
//    字符串运算符
    //BEGINSWITH、ENDSWITH、CONTAINS 分别表示是否以某字符串开头、结尾、包含。 
    //他们可以与 c、d 连用,c表示是否忽略大小写、d是否忽略重音字母(字母上方有声调标号)。
    [self doPredicateTest:marr :@"BEGINSWITH" :@"name beginswith 'zhang'"];
    [self doPredicateTest:marr :@"BEGINSWITH" :@"name beginswith[cd] 'zhang'"];
    [self doPredicateTest:marr :@"ENDSWITH" :@"name endswith 'an'"];
    [self doPredicateTest:marr :@"CONTAINS" :@"name contains 'h'"];
    
//    LIKE 运算符
    //LIKE使用?表示一个字符,*表示多个字符,也可以与 c、d 连用
    [self doPredicateTest:marr :@"LIKE" :@"name like[cd] '???ng*'"];
    
//    SELF
    //前面的数组中放的都是对象,如果数组放的都是字符串(或者是其他没有属性的类型),该怎么写谓词呢?
    //这里我们使用 SELF。
    {
        NSArray *arrays=[NSArray arrayWithObjects: @"Apple", @"Google", @"Google2", @"MircoSoft", nil]; 
        NSPredicate *pre2 = [NSPredicate predicateWithFormat:@"SELF=='Apple' or self contains 'le'"];
        int i=0;
        for(;i<[arrays count];i++){
            NSString *person=[arrays objectAtIndex: i];
            //判断对象是否符合谓词
            if ([pre2 evaluateWithObject: person]) {
                NSLog(@"%@",person);
            }
        }
    }
    
//    正则表达式
    {
        //NSPredicate 使用 MATCHES 匹配正则表达式
        //正则表达式的写法采用 international components for Unicode (ICU)的正则语法
        NSString *regex = @"^A.+e$";//以 A 开头,以 e 结尾的字符。
        NSPredicate *pre= [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; 
        if([pre evaluateWithObject: @"Apple"]){
            printf("YES\n"); 
        }
        else{
            printf("NO\n"); 
        }
    }
}


- (void)doPredicateTest:(NSArray*)arr :(NSString*)logStr :(NSString*) predicateStr{
    NSLog(@"%@", logStr);
    //构建谓词
    NSPredicate *pre = [NSPredicate predicateWithFormat:predicateStr];
    int i=0;
    for(;i<[arr count];i++){
        Person *person=[arr objectAtIndex: i];
        //判断对象是否符合谓词
        if ([pre evaluateWithObject: person]) {
            NSLog(@"%@",[person description]);
        }
    } 
}

- (void)doPredicateTest2:(NSArray*)arr :(NSString*)logStr :(NSString*) predicateStr{
    NSLog(@"%@", logStr);
    //构建谓词
    NSPredicate *pre = [NSPredicate predicateWithFormat:predicateStr];

    //快速筛选数组，判断数组中符合谓词对象
    NSArray *arrayPre=[arr filteredArrayUsingPredicate: pre]; 
    int i=0;
    for(;i<[arrayPre count];i++){
        Person *person=[arr objectAtIndex: i];
        NSLog(@"%@",[person description]);
    } 
}


#pragma mark - thread
- (IBAction)threadTest {
    //线程创建主要有3种方式：
    //1.- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
    //    这种方式是先得到线程对象，然后可以对线程对象做一些操作（比如设置线程名），然后start启动
    //    比较灵活
    //2.+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
    //  这种方式直接生成一个线程，比较简单
    //3.- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg
    //  NSObject类的方法，其他和方法2基本一样

    //线程创建方式1
    SellTickets *st=[[SellTickets alloc] init]; 
    [st setDelegate:self];
    [st ticket];   
    [st release]; 
    
    //线程创建方式2
    SellTickets2 *st2=[[SellTickets2 alloc] init]; 
    [st2 ticket:self];   
    [st2 release]; 
    
    //线程创建方式3
    SellTickets3 *st3=[[SellTickets3 alloc] init]; 
    [st3 ticket:self];   
    [st3 release]; 
}

- (void)refreshThreadTitle:(NSNumber*)i
{
    UIButton *btn = (UIButton*)[self.view viewWithTag:100];
    btn.titleLabel.font = [UIFont systemFontOfSize:10];
    if([i intValue] == 0)
    {
        [btn setTitle:@"sell tickets" forState:UIControlStateNormal];
    }
    else 
    {
        [btn setTitle:@"sell out" forState:UIControlStateNormal];
    }
}


- (IBAction)operationQueueTest {
    //对于iOS来说，建议在尽可能的情况下避免直接操作线程，使用比如NSOperationQueue这样的机制。
    //可以把NSOperationQueue看作一个线程池，可往线程池中添加操作（NSOperation）
    //NSOperation
    
    
    tickets = 10;
    
//    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//    //控制线程池中的并发的线程数
//    [queue setMaxConcurrentOperationCount: 2];
    
    SellTicketsOperation *task = [[SellTicketsOperation alloc]init];
    task.name = @"task1";
    task.tickets = &tickets;
    task.ticketsCondition = ticketsCondition;
    task.controller = self;
    [queue addOperation:task];
    [task release];
    
    task = [[SellTicketsOperation alloc]init];
    task.name = @"task2";
    task.tickets = &tickets;
    task.ticketsCondition = ticketsCondition;
    task.controller = self;
    [queue addOperation:task];
    [task release];
    
    task = [[SellTicketsOperation alloc]init];
    task.name = @"task3";
    task.tickets = &tickets;
    task.ticketsCondition = ticketsCondition;
    task.controller = self;
    //处理操作之间的依赖关系
    if ([[queue operations] count]>0) { 
        SellTicketsOperation *theBeforeTask=[[queue operations] lastObject]; 
        [task addDependency:theBeforeTask]; 
    }
    [queue addOperation:task];
    [task release];

//    [queue release];
}

#pragma mark - SELAndIMP
- (IBAction)SELAndIMP {
    Person *person= [Person personWithPid:0 Name:@"zhangsan" Height:169];
    [person print:@"*********"];
    
    //SEL 和 IMP的使用
    SEL print_sel=NSSelectorFromString(@"print:");
    NSString *selString = NSStringFromSelector(print_sel);
    NSLog(@"string of the SEL is:%@", selString);
    IMP imp=[person methodForSelector: print_sel]; 
    imp(person,print_sel,@"*********");
    
    [person release];
}


//nil: A null pointer to an Objective-C object.
//  ( #define nil ((id)0)  )
//
//Nil: A null pointer to an Objective-C class.
//
//NULL: A null pointer to anything else,  is for C-style memory pointers.
//  ( #define NULL ((void *)0)  )
//
//NSNull: A class defines a singleton object used to represent null values in collection objects(which don't allow nil values).
//  [NSNull null]: The singleton instance of NSNull.
- (IBAction)nilTest {
    {
        NSObject *obj1;
        if (obj1 != nil) 
        {
            NSLog(@"object is not nil");
        }
        else
        {
            NSLog(@"object is nil");
        }
        
        Person *c1;
        if (c1 != Nil) 
        {
            NSLog(@"class is not Nil");
        }
        else
        {
            NSLog(@"class is Nil");
        }
        
        int *money;
        if (money != NULL) 
        {
            NSLog(@"money is not NULL");
        }
        else
        {
            NSLog(@"money is NULL");
        }
    }
    
    {
        NSObject *obj1 = [[NSObject alloc] init];
        NSObject *obj2 = [NSNull null];
        NSObject *obj3 = [NSObject new];
        //NSObject *obj4;   //这句添加到array中，会出错
        NSArray *arr1 = [NSArray arrayWithObjects:obj1, obj2, obj3, nil];
        NSLog(@"arr1 count: %d", [arr1 count]);    //arr1 count: 3
        NSLog(@"%@",arr1);
        /*
         2012-06-22 15:48:38.208 TestObjc[3529:f803] arr1 count: 3
         2012-06-22 15:48:38.208 TestObjc[3529:f803] (
         "<NSObject: 0xb5393c0>",
         "<null>",
         "<NSObject: 0xb53dd10>"
         )
         */
    }
    
    {
        NSObject *obj1 = [NSNull null];
        NSArray *arr1 = [NSArray arrayWithObjects:@"One", @"TWO", obj1, @"three" ,nil];
        NSLog(@"%@",arr1);
        for (id str in arr1) {
            //-[NSNull lowercaseString]: unrecognized selector sent to instance 0x1473ce8
            if ([str isKindOfClass:[NSString class]]){
                NSLog(@"array object: %@", [str lowercaseString]);
            }
        }
    }
}


@end
